<?php
/**
 * Created by PhpStorm.
 * User: qch
 * Date: 2015/5/26
 * Time: 17:36
 */

namespace J\MVC;


use J\Schema\ICollection;
use J\Schema\Syntax;
use J\Configurable;
use J\Exception;
use J\IConfigurable;
use J\Intent;
use J\Message;
use J\Pipeline;

/**
 * 控制器基类
 *
 * @target Config
 */
class Controller implements IConfigurable
{
    use InvokeMethod;
    use Configurable;

    const AUTH_LOGIN      = 1;
    const AUTH_ADMIN      = 3;
    const AUTH_SUPER      = 7;
    const AUTH_DEPARTMENT = 8;

    const AUTH_MARK_ADMIN = 2;
    const AUTH_MARK_SUPER = 4;

    /**
     * @var string 控制器ID
     */
    protected $name;

    /**
     * @var Module
     */
    protected $module;

    /**
     * @var [] 中间件列表
     */
    protected $middleware = [];

    protected $actors = [];

    protected $filter = null;

    /**
     * 控制器构造函数
     *
     * @param Module $module 模型
     * @param string $id 名称
     * @param array $config 控制器配置
     */
    public function __construct(Module $module, $id, $config = [])
    {
        $this->module = $module;
        $this->name     = strtolower($id);
        $this->config = $this->createConfig($config, $module);

        // 继承验证
        $this->beforeCore();
        //
        $this->afterCore();
    }

    ///////////////////////////////信息处理流水线/////////////////////////////////////
    /**
     *  执行操作流水线
     *     通过抛出异常来申请返回错误页面
     * @param Intent $intent
     * @return bool|null
     */
    public function invoke(Intent $intent)
    {
        $pipeline = new Pipeline();
        return $pipeline->start(
            $this->middleware,
            /**
             * 核心中间件，自动搜索方法
             */
            function(Intent $intent){
                return $this->invokeIntentMethod($intent);
            }, $intent
        );
    }

    /**
     * 扩展接口, 优先的中间件在这里添加
     */
    protected function beforeCore()
    {
        $this->addMiddleware('Debugger');
    }

    /**
     * 扩展接口，收尾的中间件在这里添加
     */
    protected function afterCore()
    {
        $this->addMiddleware(function (\Closure $next)
        {
            /**
             * 默认收尾中间件：自动渲染模板
             *
             * @param Intent $intent
             * @return null|bool
             */
            return function (Intent $intent) use ($next) {
                $r = $next($intent);
                if ($r !== false) return $r;

                try {
                    $intent->value = $this->getView(
                        $intent->action,
                        $this->getInformation($intent, 'assign')
                    );
                    return null;
                } catch (\Throwable $e) {
                    return false;
                }
            };
        });
    }

    //////////////////////////////////视图处理部分/////////////////////////////////
    /**
     * 渲染操作
     *
     * @param string $view
     * @param [] $arguments
     * @return bool
     * @internal param Intent $intent
     * @throws Exception
     */
    public function getView($view, $arguments)
    {
        return  View::display($view, [
            $this->module->getVir() . DS .$this->name,
            DEFAULT_VIR .DS .$this->module->getName(). DS .$this->name
        ], $arguments);
    }

    /////////////////////////////接口/////////////////////////////////////
//    /**
//     * 上级可配置对象
//     *
//     * @return IConfigurable
//     */
//    public function getUpper()
//    {
//        return $this->module;
//    }

    //////////////////////////////操作//////////////////////////////////
    /**
     * 获取集合对象
     *
     * @param string $collection 集合名称
     * @return ICollection
     * @throws Exception
     */
    public function getCollection($collection = null)
    {
        if ($collection === null) $collection = $this->getName();
        return $this->module->getModels()->getCollection($collection);
    }

    /**
     * @return string 索引
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @return Department 部门校验工具
     */
    public function getDepartment()
    {
        return null;
    }

    /**
     * @return Module 模块
     */
    public function getModule()
    {
        return $this->module;
    }

    /**
     * @return \J\Application 应用
     */
    public function getApp()
    {
        return $this->module->getApp();
    }

    /**
     * 启用管理员权限校验
     *
     * @param int $admin
     */
    public function enableAdmin($admin = self::AUTH_ADMIN)
    {
        // 用户登录
        $this->addMiddleware(function (\Closure $next) {
            return $this->getApp()->User()->getLoginMiddleware($next);
        });

        if ($admin & self::AUTH_MARK_ADMIN) {
            // 管理员
            $this->addMiddleware(function (\Closure $next)
            {
                return $this->getApp()->User()->getAdminMiddleware($next);
            });

            // 超级管理员
            if ($admin & self::AUTH_MARK_SUPER) {
                $this->addMiddleware(function (\Closure $next) {
                    return function (Intent $intent) use ($next) {
                        if ($this->getApp()->User()->isAdministrator())
                            return $next($intent);
                        throw new Exception(Message::SUPER_MUST);
                    };
                });
            }
        }
    }

    /**
     * 根据当前意图获取配置信息
     *
     * @param Intent $intent
     * @param string $key
     * @param array $default
     * @return mixed|null
     */
    public function getInformation($intent, $key = null, $default = [])
    {
        $action = strtolower($intent->action);
        $information = $this->get(Syntax::KEY_OPTIONS.'.'.strtolower($action), $default, false);

        if($key === null) return $information;

        return array_isset($information, $key, $default);
    }

    /**
     * 添加中间件
     *
     * @param \Closure|string $middleware
     */
    public function addMiddleware($middleware)
    {
        $this->middleware[] = $middleware;
    }


    public function debug($message, $context = array())
    {
        return $this->getApp()->debug($message, $context);
    }

    public function error($message, $context = array())
    {
        return $this->getApp()->error($message, $context);
    }

    /**
     * @return Filter
     */
    public function getFilter()
    {
        if (null === $this->filter) {
            $this->filter = new Filter();
        }
        return $this->filter;
    }
}